package gamebase.core;

import java.awt.Graphics2D;
import java.util.ArrayList;
import java.util.Hashtable;

/**
 * Node is the parent class of all objects in the node system. Each node object
 * has one parent and zero or more children. It has immediate access to both its
 * parent and its children.
 * 
 * @author dylan
 */
public abstract class Node {
	private Node parent;
	private ArrayList<Node> children;
	private Hashtable<String, Double> properties;
	/**
	 * Set to a different number for each subclass of Node, allowing easy
	 * identification.
	 */
	public static int ID = 0;

	/**
	 * Can have child nodes by default. If false, adding a child will do
	 * nothing.
	 */
	protected boolean canHaveChildren = true;

	/**
	 * Can have parent nodes by default. If false, setting the parent will do
	 * nothing.
	 */
	protected boolean canHaveParent = false;

	/**
	 * If false, none of the current node's children will be visible.
	 */
	protected boolean visible = true;

	public Node() {
		// Initialize variables.
		children = new ArrayList<Node>();
		properties = new Hashtable<String, Double>();
	}

	/**
	 * Set a new parent node for the current node. Returns true if successful.
	 * 
	 * @param newParent
	 *            - The new parent node
	 * @return boolean
	 */
	public boolean setParent(Node newParent) {
		if (canHaveParent) {
			parent = newParent;
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Add a new child Node to the current node. Returns true if successful.
	 * 
	 * @param newChild
	 *            - The new child node
	 * @return boolean
	 */
	public boolean addChild(Node newChild) {
		if (canHaveChildren) {
			children.add(newChild);
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Remove the specified child Node from the current node's children. Returns
	 * true if successful.
	 * 
	 * @param deadChild
	 *            - The child node to be removed
	 * @return boolean
	 */
	public boolean removeChild(Node deadChild) {
		if (canHaveChildren) {
			return children.remove(deadChild);
		} else {
			return false;
		}
	}

	/**
	 * Send an event either to the parent, to all the children, or to no one,
	 * depending on the value of direction.
	 * 
	 * @param event
	 *            - The event to be sent
	 * @param direction
	 *            - The direction in the tree it will be sent in
	 */
	public void sendEvent(Event event, int direction) {
		if (direction == Event.UP) {
			if (parent != null) {
				parent.recieveEvent(event);
			}
		} else if (direction == Event.DOWN) {
			for (Node child : children) {
				child.recieveEvent(event);
			}
		} else if (direction == Event.DONE) {
			return;
		} else {
			System.err.println("checkNode returned an unrecognized value.");
		}
	}

	/**
	 * Receive an event, let the event run on the current node, and then pass it
	 * up or down as required.
	 * 
	 * @param event
	 *            - The event being received
	 */
	public void recieveEvent(Event event) {
		sendEvent(event, event.checkNode(this));
	}

	/**
	 * The method called by the Draw event. If the node is visible, it calls draw(), otherwise it returns false.
	 * DO NOT override this method.
	 * 
	 * @param g - A Graphics2D object
	 * @return boolean
	 */
	public boolean _draw(Graphics2D g) {
		if (visible) {
			draw(g);
			return true;
		} else {
			return false;
		}
	}
	
	/**
	 * Draw any graphics associated with the node.
	 * 
	 * @param g - A Graphics2D object
	 */
	public void draw(Graphics2D g) {
	}
	
	public void setProperty(String name, double value){
		if (properties.containsKey(name)){
			properties.remove(name);
		}
		properties.put(name, value);
	}
}
